﻿using Assimp;
using Assimp.Configs;
using OpenTK.Mathematics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OpenTKBasics.AssimpNet
{
    public class Model2
    {
        private List<Mesh> myMeshes = new List<Mesh>();
        private List<Assimp.Mesh> meshes = new List<Assimp.Mesh>();
        private Shader _shader;

        public Model2(Shader shader, string path)
        {
            this._shader = shader;
            LoadModel(path);
        }

        void LoadModel(string path)
        {
            string directory = Path.GetDirectoryName(path);
            Console.WriteLine(directory);

            //Filepath to our model String fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Seymour.dae");

            //Create a new importer
            AssimpContext importer = new AssimpContext();

            //This is how we add a configuration (each config is its own class)
            NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f);
            importer.SetConfig(config);

            //This is how we add a logging callback 
            LogStream logstream = new LogStream(delegate (String msg, String userData)
            {
                Console.WriteLine(msg);
            });
            logstream.Attach();

            //Import the model. All configs are set. The model
            //is imported, loaded into managed memory. Then the unmanaged memory is released, and everything is reset.
            Scene scene = importer.ImportFile(
                path,
                PostProcessPreset.TargetRealTimeMaximumQuality
                | PostProcessSteps.PreTransformVertices
                | PostProcessSteps.Triangulate
                | PostProcessSteps.FlipUVs
                | PostProcessSteps.CalculateTangentSpace
                );

            if (scene == null || scene.SceneFlags == SceneFlags.Incomplete || scene.RootNode == null)
            { Console.WriteLine("ERROR::ASSIMP"); return; }

            Console.WriteLine("================Model_Loaded");
            //TODO: Load the model data into your own structures

            ProcessNode(scene.RootNode, ref scene);

            Console.WriteLine("================ProcessNode_Done");

            //End of example
            importer.Dispose();

            //AssimpOperator assimpOperator = new AssimpOperator();
            //assimpOperator.LoadFile(path);
             myMeshes = meshes.Select(m => ProcessMesh(m)).ToList();
        }

        void ProcessNode(Node node, ref Scene scene)
        {
            Console.WriteLine(node.Name);

            foreach (int num in node.MeshIndices)
            {
                meshes.Add(scene.Meshes[num]);
            }

            foreach (Node item in node.Children)
            {
                ProcessNode(item, ref scene);
            }
        }

        Mesh ProcessMesh(Assimp.Mesh mesh)
        {
            List<Vertex> tempVertices = new List<Vertex>();
            List<uint> tempIndices = new List<uint>();
            List<Texture> tempTextures = new List<Texture>();

            //Vector3 tempVec;

            for (int i = 0; i < mesh.VertexCount; i++)
            {
                Vertex tempVertex = new Vertex();

                Vector3D vert = mesh.Vertices[i];
                tempVertex.Position.X = vert.X;
                tempVertex.Position.Y = vert.Y;
                tempVertex.Position.Z = vert.Z;

                Vector3D norm = mesh.Normals[i];
                tempVertex.Normal.X = norm.X;
                tempVertex.Normal.Y = norm.Y;
                tempVertex.Normal.Z = norm.Z;

                if (mesh.HasTextureCoords(0))
                {
                    tempVertex.TexCoords.X = mesh.TextureCoordinateChannels[0][i].X;
                    tempVertex.TexCoords.Y = mesh.TextureCoordinateChannels[0][i].Y;
                }
                else
                {
                    tempVertex.TexCoords = new Vector2(0.0f, 0.0f);
                }

                tempVertices.Add(tempVertex);
            }

            //foreach (int i in mesh.Faces.SelectMany(f => f.Indices))
            //{
            //    tempIndices.Add((uint)i);
            //}

            for (int i = 0; i < mesh.FaceCount; i++)
            {
                for (int j = 0; j < mesh.Faces[i].IndexCount; j++)
                {
                    tempIndices.Add((uint)mesh.Faces[i].Indices[j]);
                }
            }

            //Mesh myMesh = new Mesh(this._shader,tempVertices.ToArray(), tempIndices.ToArray(), new Texture[0]);
            //myMesh.SetShader(this._shader);

            return new Mesh(this._shader, tempVertices.ToArray(), tempIndices.ToArray(), tempTextures.ToArray());
        }

        public void Draw()
        {
            myMeshes.ForEach(m => m.Draw());
        }

    }
}
